home *** CD-ROM | disk | FTP | other *** search
/ BBS Toolkit / BBS Toolkit.iso / rbbs_pc / 173basm.zip / QBARCV6.ASM < prev    next >
Assembly Source File  |  1989-09-03  |  46KB  |  1,688 lines

  1.     page    74,132
  2.     title    ARCV - Verbose ARC directory listing
  3.  
  4. ;    Special version of ARCV to be called by QB program
  5. ; usage:
  6. ;
  7. ;    CALL ARCV (Workname$,"filename[.PAK]", RETCD%)             ' CPC151AC
  8. ;
  9. ; notes:
  10. ;    This code originated from ARCV 1.15d - Verbose ARC directory display
  11. ;    written by V.Buerg and was modified to run as a called routine under
  12. ;    Microsoft QuickBasic. It was further modified to allow PAK files by
  13. ;    Robert J. Simoneau.
  14. ;
  15. ;    Change 9/14/86 to dis-allow wildcards
  16. ;    Change 1/1/87 to recognize squash format
  17. ;    Change 2/18/87 to support network usage - - - - Jon Martin   ' CPC151A
  18. ;    Change 1/7/89 to support Pak files -------------Bob Simoneau
  19.  
  20. ;    Change 890320 to support ZIP files    David Kirschbaum, Toad Hall
  21. ;    - Question:  Why do we "have to look for the damned thing" when it
  22. ;      comes to finding ARC/PAK headers?  All comments are at file ends,
  23. ;      so the header should be EXACTLY where it should be .. at the end of
  24. ;      the file's compressed code.  Hacked severely to reflect this,
  25. ;      and vastly cleaning up the code.
  26. ;    - Replaced old SDIR Binary to Ascii conversion with a hacked version
  27. ;      from JMODEM .. about 10 times faster, plus offers integer conversion
  28. ;      as well as long integers.
  29. ;v1.3    - FAAR RBBS reports this sucker runs once and then just returns
  30. ;      a usage message (in the output file).
  31. ;      Trying to find out why.  Found it .. dumb mistake, not clearing
  32. ;      variables between runs.
  33. ;    - Adding true EOF testing for file pointer bumps.
  34. ;      ZIP files have a good way to find EOF (e.g., the central directory),
  35. ;      but PAK and ARC files don't.
  36. ;    - Added some more error msgs.
  37. ;    - Tightened hex output (CvH).
  38. ;    - Reduced buffer sizes to minimum (archdr and inbuf).
  39. ;
  40. ;v1.4    - Adding the new Japanese .LHZ capability.    Toad Hall
  41. ;      See LHARC10E.ZIP (available on GEnie and BBS's) for details.
  42. ;    - Neatening up total line.
  43. ;    - Found some bugs in trying to predetermine ARC/PAK EOF.
  44. ;      Fixed (hopefully).
  45. ;    - Added a bunch of [bx] references .. saved 100 bytes!
  46. ;    - Credits for LHARC (.LHZ) file header structure to:
  47. ;        Daniel Durbin
  48. ;        SysOp: Cygnus X-1 BBS        | CIS: 73447,1744
  49. ;        (805) 541-8505 (data)        | GEnie: D.DURBIN
  50. ;        EL major at PolySlo        | ddurbin@polyslo.CalPoly.EDU 
  51. ;      from his LVIEW.C code.
  52. ;
  53. ;Fix    - Correct bug that kept version 1.4 from functioning when linked
  54. ;08/23/89 with RBBS-PC that had been compiled using QB4.5 compiler.
  55. ;         As it turned out it was an out and out bug that just did not
  56. ;         happen to crash when RBBS-PC was compiled using QB3.0.
  57. ;       
  58. ;         Jon Martin AIRCOMM (415) 689-2090
  59. ;
  60. ;Fix    - Correct bug that did not support Implode as valid ZIP compression
  61. ;09/02/89 type.                                                    
  62. ;       
  63. ;         Jon Martin AIRCOMM (415) 689-2090
  64. ;
  65. STDOUT    equ    1            ;Standard Output        v1.3
  66. STDERR    equ    2            ;Std Error (console)        v1.3
  67. FALSE    equ    0
  68. TRUE    equ    NOT FALSE
  69. DEBUG    equ    FALSE
  70.  
  71. Print    macro    name            ; display a field
  72.     mov    dx,offset name
  73.     call    PrintS
  74.     endm
  75.  
  76. header  struc                ; archive header
  77. aMbrflag    db    1AH        ;unique ARC/PAK flag        v1.3
  78. aCmpMeth    db    0        ;  compression code
  79. aMbrName    db    13 dup (0)    ;  file name
  80. aCmpSiz        dw    0,0        ;  file size in archive
  81. aModDate    dw    0        ;  creation date
  82. aModTime    dw    0        ;  creation time
  83. aCrc16        dw    0        ;  cyclic redundancy check
  84. aUncmpSiz    dw    0,0        ;  true file size, bytes
  85. header  ends
  86.  
  87. ARCHDRLEN    equ    29        ;size of ARC/PAK header.    v1.3
  88.  
  89. ;v1.3    ZIP Local file header structure:
  90.  
  91. zLocalEntry    STRUC
  92.   
  93. zdig0    db    50H,4BH,03H,04H    ;local file header signature    4 bytes
  94.                 ;(0x04034b50)
  95. zVerMade    dw    ?    ;version needed to extract    2 bytes
  96. zBitflag    dw    ?    ;general purpose bit flag    2 bytes
  97. zCmpMeth    dw    ?    ;compression method        2 bytes
  98. zModTime    dw    ?    ;last mod file time         2 bytes
  99. zModDate    dw    ?    ;last mod file date        2 bytes
  100. zCrc32        dw    ?,?    ;crc-32               4 bytes
  101. zCmpSiz        dw    ?,?    ;compressed size        4 bytes
  102. zUncmpSiz    dw    ?,?    ;uncompressed size        4 bytes
  103. zNameLen    dw    ?    ;filename length        2 bytes
  104. zExtraLen    dw    ?    ;extra field length        2 bytes
  105. zMbrName    db    ?    ;filename (variable size)
  106.                 ;extra field (variable size)
  107. ZLocalEntry    ENDS
  108.  
  109. ZIPHDRLEN    equ    30        ;length of initial ZIP hdr read    v1.3
  110.  
  111. ;v1.4    LZH header structure
  112.  
  113. lzhlfh    STRUC            ;Local file header
  114. lUnk1        db    ?,?    ;char unknown1[2];    ;?
  115. lCmpMeth    db    5 dup(?) ;char method[5];    ;compression method
  116. lCmpSiz        dw    ?,?    ;long csize;    ;compressed size
  117. lUncmpSiz    dw    ?,?    ;long fsize;    ;uncompressed size
  118. lModTime    dw    ?    ;int ftime;    ;last mod file time
  119. lModDate    dw    ?    ;int fdate;    ;last mod file date
  120. lFAttr        db    ?    ;char fattr;    ;file attributes
  121. lUnk2        db    ?    ;char unknown2;    ;?
  122. lNameLen    db    ?    ;char namelen;    ;filename length
  123. lMbrName    db    ?    ;char *fname;    ;filename
  124. ;lCrc16        dw    ?        ;int crc;    ;crc-16
  125. lzhlfh    ENDS
  126.  
  127. LZHHDRLEN    equ    22    ;not including lMbrName or lCrc16
  128.  
  129.  
  130. CSEG    segment public para 'CODE'
  131.     assume    CS:CSEG,DS:CSEG,ES:CSEG
  132.  
  133.     public  ArcV
  134.  
  135. ArcV    proc    far
  136.     push    bp            ; save BASIC reg
  137.     mov    bp,sp            ; get parameter list pointer
  138.     mov    CS:stkptr,sp        ; save stack ptr
  139.     mov    CS:saveds,DS        ; save QB seg reg
  140.     mov    CS:savees,ES        ; save QB seg reg
  141.     call    Start            ; do our thing            v1.3
  142.  
  143. ;    set DOS error level and exit
  144. ;v1.3a    We aren't relying on the CF flag anymore to indicate errors.
  145. ;    Instead, check AL.
  146. ;    0 = success
  147. ;    1 = command line parm error
  148. ;    2..6 are file-related (not found, etc.)
  149. ;    11 = Invalid format (probably didn't find a member header)
  150. ;    13 = invalid data (probably a bad file header structure)
  151. ;    18 = Unexpected EOF ('no further files to be found')
  152.  
  153. Exit:    mov    sp,stkptr        ; restore entry stack value
  154.  
  155.     push    ax            ;save error value        v1.3
  156.  
  157. ;v1.3    Numerous errors could be returned
  158.  
  159.     or    al,al            ;no errors?
  160.     jz    Exit_NoErr        ;yep, ok
  161.  
  162.     mov    bx,offset errtbl    ;assume unknown error
  163.     mov    di,bx            ;various error values
  164.     mov    cx,ERRTBLLEN        ;table length
  165.     repne    scasb            ;find the offset
  166.     jnz    Err_TblDone        ;unknown, BX has table start
  167.  
  168.      dec    di            ;back up to actual error
  169.      sub    di,bx            ;current psn - start = relative nr
  170.      mov    bx,di            ;into BX for msg offset
  171.  
  172. Err_TblDone:
  173.     shl    bx,1            ;*2 for words
  174. Err_Unk:
  175.     add    bx,offset errmsgtbl    ;table of addresses
  176.     mov    dx,[bx]            ;ptr to string
  177.     call    PrintS            ;output error msg
  178.         
  179. Exit_NoErr:
  180.  
  181.     mov    bx,word ptr outhdl    ; close listing file
  182.     cmp    bl,STDERR        ;never opened or STDERR?    v1.3
  183.     jna    Exit1            ;not a real handle        v1.3
  184.      mov    ah,3eh            ;close file handle
  185.      int    21h
  186. Exit1:
  187.     mov    bx,word ptr archdl    ;close ARC/PAK/ZIP file        v1.3
  188.     or    bx,bx            ; if it was opened        v1.3
  189.     jz    Exit2            ; nope                v1.3
  190.      mov    ah,3EH            ;close file handle        v1.3
  191.      int    21H            ;                v1.3
  192. Exit2:                    ;                v1.3
  193.  
  194. ;v1.3    Adding a test to insure we switched DTAs
  195. ;    (so we don't blow away the caller's DTA with a vector 0:0!)
  196.  
  197.     lds    dx,dword ptr savedta    ;get orig DTA vector
  198.     or    dx,dx            ;did we ever get it?
  199.     jz    Exit_NoDTA        ;nope
  200.     mov    ax,DS            ;check out seg
  201.     or    ax,ax
  202.     jz    Exit_NoDTA        ;nope
  203.      mov    ah,1ah            ;set DTA
  204.      int    21h
  205. Exit_NoDTA:
  206.  
  207.     les    ax,dword ptr CS:saveds    ;recover calling seg regs    08/23/89
  208.                     ;(low word is orig DS)         08/23/89
  209.     mov    ds,ax                   ;                            08/23/89
  210.     ASSUME    DS:NOTHING,ES:NOTHING    ;a reminder
  211.  
  212.     pop    ax            ;restore error level        v1.3
  213.     xor    ah,ah            ;insure msb clear        v1.3a
  214.  
  215.     mov    bp,sp            ; parm ptr from entry
  216.     mov    6[bp],ax        ;return retcd variable        v1.3
  217.     pop    bp
  218.     ret    6            ; clear parms from stack     ' CPC151A
  219.  
  220.     subttl    '--- constants, equates and work areas'
  221.     page
  222.  
  223. CR    equ    13
  224. LF    equ    10
  225. BEL    equ    7
  226. TAB    equ    9
  227.  
  228. STOPPER equ    0        ; end of display line indicator
  229. ARCMARK equ    26        ; special archive marker
  230. ARCVER  equ    10        ; highest compression code used
  231.  
  232.     even            ;v1.3a
  233.  
  234. stkptr  dw    0        ; stack pointer upon entry
  235.  
  236. arctitl db    CR,LF,'Archive:  '    ;keep this even            v1.3a
  237. saveds  dw    0        ; QB seg reg
  238. savees  dw    0        ; QB seg reg
  239.  
  240.     subttl    '--- i/o control variables'
  241.     page
  242.  
  243. INBUFSZ equ    128    ;512    ; size of input buffer            v1.3
  244.  
  245. ;v1.3    Completely reordered these runtime variables
  246. ;    so we can purge them with one fell swoop
  247.  
  248. PURGESTART    equ    $    ;                    v1.3
  249.  
  250. totsf    dw    0,0        ; average stowage factor
  251. totlen  dw    0,0        ; total of file lengths
  252. totsize dw    0,0        ; total of file sizes
  253. totmbrs dw    0        ; total number of files
  254.  
  255. archdl  dw    0        ; file handle
  256. fileptr dw    0        ; ptr to filename part of arcname
  257. arclen    dw    0        ;full archive filename length        v1.3
  258. arcname db    76 dup (0)
  259.  
  260. outhdl  dw    0        ; handle for output listing        v1.3
  261. templen    dw    0        ;output filename length            v1.3
  262. temp    db    76 dup (0)    ; and temporary file name
  263.  
  264. filelen    dw    0,0        ;absolute archive file length        v1.3a
  265. curpsn    dw    0,0        ;remember current file pointer psn    v1.3a
  266.  
  267. savedta dw    0,0        ; addr of QB dta
  268. dta    db    48 dup (0)    ; data transfer area
  269.  
  270.     even            ;                    v1.3
  271.  
  272. PURGELEN    EQU    ($ - PURGESTART) SHR 1    ;amount to purge each run v1.3
  273.  
  274. ;    display lines for verbose
  275.  
  276. vhdr    db    CR,LF
  277.  db CR,LF,'Name          Length    Stowage    SF   Size now  Date       Time    CRC '
  278.  db CR,LF,'============  ========  ========  ====  ========  =========  ======  ===='
  279.  db CR,LF            ;v1.4
  280.  db STOPPER
  281.  
  282. ;vline    db    CR,LF
  283. vline    label    byte        ;v1.4
  284. vname    db    14 dup (' ')
  285. vlength db    '          '    ; length in archive            v1.3
  286. vstyle  db    '          '    ; compression method
  287. vfactor db    ' xx%  '    ; compression factor
  288. vsize    db    10 dup (' ')    ; actual file bytes
  289. vdate    db    'dd '        ; creation date
  290.  vmonth db    'mmm '
  291.  vyear  db    'yy  '
  292.  vtime  db    'hh:mm   '    ; creation time
  293.  vcrc    db    'xxxx'        ; crc in hex
  294.     db    CR,LF        ;v1.4
  295.     db    STOPPER
  296.  
  297. hundred dw    100        ; for computing percentages
  298.  
  299. ;    final totals line
  300.  
  301. vthdr    db '------    --- --------            ----  --------',CR,LF    ;v1.4
  302.     db    '*Total    '                        ;v1.4
  303.  vtmbrs db    '    '
  304.  vtlen  db    8 dup (' '),'  '
  305.     db    10 dup (' ')
  306.  vtsf    db    '   %  '
  307.  vtsize db    8 dup (' ')
  308.     db    CR,LF        ; for tom
  309.     db    STOPPER
  310.  
  311.  sign    db    ' '
  312.  
  313. styles  db    '  ----- '    ; 1 = old, no compression
  314.     db    '  ----- '    ; 2 = new, no compression
  315.     db    ' Packed '    ; 3 = dle for repeat chars
  316.     db    'Squeezed'    ; 4 = huffman encoding
  317.     db    'crunched'    ; 5 = lz, no dle
  318.     db    'crunched'    ; 6 = lz with dle
  319.     db    'Crunched'    ; 7 = lz with readjust
  320.     db    'Crunched'    ; 8 = lz with readjust and dle
  321.     db    'Squashed'    ; 9 = 13-bit lz with no dle
  322.     db    ' Crushed'    ;10 = Pak10 file ---------Bob Simoneau
  323.  
  324. ;v1.3    ZIP compression types:
  325.  
  326. zstyles    label    byte
  327.     db    '  Stored'    ;0 - The file is stored (no compression)
  328.     db    '  Shrunk'    ;1 - The file is Shrunk
  329.     db    'Reduced1'    ;2 - Reduced with compression factor 1
  330.     db    'Reduced2'    ;3 - Reduced with compression factor 2
  331.     db    'Reduced3'    ;4 - Reduced with compression factor 3
  332.     db    'Reduced4'    ;5 - Reduced with compression factor 4
  333.         db      'Imploded'      ;6 - New don't know format              v1.6
  334.  
  335. ;v1.4    LZH compression types are already coded as 5 chars of text
  336. ;    in the compressed file.
  337. ;    All we need to do is pad them out to the correct width.
  338.  
  339. months  db    'Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec '
  340.  
  341. ARCPAK    =    0            ;                v1.3
  342. ZIP    =    1            ;                v1.4
  343. LZH    =    2            ;                v1.4
  344. ftype    db    ZIP            ;flag which type file        v1.3
  345.  
  346. ;v1.4    4 types of archive file
  347.  
  348. ziptype    db    'ZIP'
  349. arctype    db    'ARC'
  350. paktype    db    'PAK'
  351. lzhtype    db    'LZH'            ;v1.4
  352. larctype db    'LZS'            ;v1.4 not enabled for now
  353.  
  354. ;zfilesig db    50H,4BH,03H,04H        ;local file header signature    v1.3
  355. ;zdirsig db    50H,4BH,01H,02H        ;central file header signature    v1.3
  356.  
  357. ZSIG    equ    4B50H            ;unique ZIP signature        v1.4
  358. ZFILESIG equ    0403H            ;file member signature        v1.4
  359. ZDIRSIG    equ    0201H            ;central file header signature    v1.4
  360.  
  361. ;v1.3    Centralizing errors at the exit point
  362.  
  363. ;    1 = command line parm error
  364. ;    2..6 are file-related (not found, etc.)
  365. ;    11 = Invalid format (probably didn't find a member header)
  366. ;    12 = Invalid file type (not an ARC, PAK, ZIP)
  367. ;    13 = invalid data (probably a bad file header structure)
  368. ;    18 = Unexpected EOF ('no further files to be found')
  369.  
  370. errtbl db    0,1,2,3,4,5,6,11,12,13,18,25,27,29,30            ;v1.3a
  371. ERRTBLLEN    equ    $ - errtbl
  372.  
  373. errmsgtbl dw    msg0,msg1,msg2,msg3                    ;v1.3a
  374.     dw    msg4,msg5,msg6,msg11
  375.     dw    msg12,msg13,msg18,msg25
  376.     dw    msg27,msg29,msg30
  377.  
  378. msg0    db    'Unknown error',0
  379.  
  380. msg1    db    'Invalid function number',0
  381. msg2    db    'Archive file not found',0
  382. msg3    db    'Path not found',0
  383. msg4    db    'No handle available',0
  384. msg5    db    'Access denied',0
  385. msg6    db    'Invalid handle',0
  386. msg11    db    'Archive header error',0
  387. msg12    db    'Invalid file type',0
  388. msg13    db    'Archive format error',0
  389. msg18    db    'No further files to be found',0
  390. msg25    db    'Disk seek error',0
  391. msg27    db    'Disk sector not found',0
  392. msg29    db    'Write error',0
  393. msg30    db    'Read error',0
  394.  
  395.  
  396.     subttl    '--- mainline processing'
  397.     page
  398. ;
  399. Start    proc    near            ;                v1.3
  400.  
  401.     mov    ax,CS            ;just set ES for now        v1.3
  402.     mov    ES,ax
  403.     ASSUME    DS:NOTHING,ES:CSEG    ;a reminder            v1.3a
  404.  
  405. ;v1.3    Insure all variables are cleared
  406.     cld
  407.     mov    di,offset PURGESTART
  408.     xor    ax,ax            ;clear all the variables    v1.3
  409.     mov    cx,PURGELEN        ;nr words to clear        v1.3
  410.     rep    stosw            ;                v1.3
  411.  
  412. ;v1.3    Move first parameter (output filename) into code space
  413.  
  414.     mov    si,word ptr 10[bp]    ; ptr to parameter vector    ' CPC151A
  415.     lodsw                ; get string length         ' CPC151A
  416.     mov    cx,ax            ;                 ' CPC151A
  417.     jcxz    Copy_Parm2        ;empty, forget it        v1.3
  418.      mov    di,offset templen    ;str length            v1.3
  419.      stosw                ;save length            v1.3
  420.      mov    si,[si]            ; get string offset        v1.3a
  421.      rep    movsb            ;copy in the string        v1.3
  422.  
  423. Copy_Parm2:
  424.  
  425. ;v1.3    Now copy 2d parameter (target archive filename)
  426.  
  427.     mov    si,word ptr 8[bp]    ; ptr to parameter vector
  428.     lodsw                ; get string length
  429.     mov    cx,ax            ;                v1.3
  430.     jcxz    Parm2_Done        ;forget it            v1.3
  431.      mov    di,offset arclen    ;archive name length        v1.3
  432.      stosw                ;save length            v1.3
  433.      mov    si,[si]            ; get string offset        v1.3
  434.      mov    ah,'a'            ;constant for uppercasing    v1.3
  435. Parm2_Upper:                ;                v1.3
  436.      lodsb                ;snarf char            v1.3
  437.      cmp    al,ah            ;need uppercasing?        v1.3
  438.      jb    Parm2_NoU        ;nope                v1.3
  439.       sub    al,20H            ;uppercase it            v1.3
  440. Parm2_NoU:                ;                v1.3
  441.      stosb                ;                v1.3
  442.      loop    Parm2_Upper        ;                v1.3
  443.  
  444. Parm2_Done:
  445.  
  446. ;v1.3    All done with DS
  447.  
  448.     mov    ax,CS            ;                v1.3
  449.     mov    DS,ax            ;                v1.3
  450.     ASSUME    DS:CSEG,ES:CSEG        ;a reminder            v1.3a
  451.  
  452.     mov    ax,STDERR        ;assume no output filename    v1.3a
  453.     cmp    temp,0            ;any output filename?        v1.3
  454.     jz    Temp_Opened        ;nope, use STDERR        v1.3a
  455.  
  456. ;v1.3    Forcing output file to STDERR for debugging.
  457. ;v1.3     mov    al,1            ; will show usage        v1.3
  458. ;v1.3     ret                ;back to Exit            v1.3
  459.  
  460. ;v1.3a     mov    ax,STDERR        ;force to STDERR        v1.3
  461. ;v1.3a     jmp    short Temp_Opened    ;continue            v1.3
  462.  
  463. ;Got_Temp:
  464.     mov    dx,offset temp        ; open temporary file for output
  465.     xor    cx,cx            ;no special attributes        v1.3
  466.     mov    ah,3ch            ;create file
  467.     int    21h
  468.     jnb    Temp_Opened        ;fine                v1.3
  469.      ret                ;back to Exit, AL=error code    v1.3
  470.                     ;CF set                v1.3a
  471. Temp_Opened:
  472.     mov    outhdl,ax        ;save handle
  473.  
  474. ;v1.3    Parse the target archive name
  475. ;    Separate path from name
  476. ;    Insure it's an ARC, PAK or ZIP type.
  477.  
  478.     mov    di,offset arclen    ;archive name length        v1.3
  479.     mov    ax,[di]            ;snarf length            v1.3a
  480.     inc    di            ;bump to name proper        v1.3a
  481.     inc    di            ;                v1.3a
  482.     mov    cx,ax            ;into CX for scans to come    v1.3a
  483.     jcxz    No_ArcName        ;no length, ergo no name    v1.3a
  484.  
  485.     mov    dx,ax            ;save in DX for later        v1.3
  486.     xor    al,al            ;will scan for AsciiZ terminator v1.3
  487.     cmp    [di],al            ;no name at all?        v1.3
  488.     jnz    Got_ArcName        ;yep                v1.3
  489.  
  490. No_ArcName:
  491.      mov    al,2            ;'Archive file not found'    v1.3
  492.      ret                ;back to Exit            v1.3
  493.  
  494. Got_ArcName:
  495.  
  496. ;v1.3    We have some sort of target name.
  497. ;    But is it a legal type?
  498. ;    DX = filename length
  499. ;    DI -> archive filename (arcname)
  500.  
  501.     add    di,dx            ;+ length -> last char+1    v1.3
  502.     dec    di            ;back up to last char        v1.3
  503.     mov    bx,di            ;BX -> last char        v1.3
  504.  
  505.     mov    al,'\'            ;look for normal path delimiter    v1.3
  506.     mov    cx,dx            ;length for scan        v1.3
  507.     std                ;backwards scanning now        v1.3
  508.     repne    scasb            ;                v1.3
  509.     jz    Got_Start        ;found one            v1.3
  510.  
  511. ;Ugh .. tired of typing in v1.3's!
  512.  
  513.     mov    di,bx            ;back to end
  514.     mov    cx,dx            ;restore length
  515.     mov    al,'/'            ;funny path delimiter
  516.     repne    scasb
  517.     jz    Got_Start        ;found one
  518.  
  519.     mov    di,bx            ;back to end .. sigh ..
  520.     mov    cx,dx            ;restore length
  521.     mov    al,':'            ;ok, how about a drive?
  522.     repne    scasb
  523.     jnz    No_Paths        ;nope, DI -> name start
  524.  
  525. Got_Start:
  526.     inc    di            ;bump up to the separator
  527. No_Paths:
  528.     inc    di            ;bump to the first name char
  529.     cld                ;forward again
  530.     mov    fileptr,di        ;remember real filename start
  531.  
  532. ;v1.4    You MUST specify the type .. .ARC, .PAK, .ZIP, or .LZH.
  533. ;    If .ARC or .PAK, we'll use the old code to display ARC-type
  534. ;    files.
  535. ;v1.4    Else if ZIP or LZH, it's a totally new format!
  536. ;    We remember the type archiving format in 'ftype'.
  537.  
  538. ;v1.3    DS:SI -> filename's first char.
  539.  
  540.     mov    al,'.'            ;find the separator        v1.3
  541.     mov    cx,word ptr 12        ;max of 12 chars        v1.3
  542.     repne    scasb            ;find it            v1.3
  543.     jnz    BadType            ;forget it            v1.3
  544.  
  545.     mov    dx,di            ;save pointer to file type    v1.3
  546.                     ;(just past the separator)    v1.3
  547.     mov    ax,3            ;3 chars constant
  548.  
  549.     mov    ftype,ZIP        ;assume ZIP
  550.  
  551.     mov    si,offset ziptype    ;is it a ZIP?
  552.     mov    di,dx            ;back to filename type
  553.     mov    cx,ax            ;3 chars
  554.     repz    cmpsb            ;compare
  555.     jz    Got_Type        ;a match
  556.  
  557.     mov    ftype,ARCPAK        ;ok, assume ARC or PAK        v1.3a
  558.  
  559.     mov    si,offset arctype    ;is it an ARC?            v1.3
  560.     mov    di,dx            ;back to filename type
  561.     mov    cx,ax            ;3 chars
  562.     repz    cmpsb            ;compare
  563.     jz    Got_Type        ;a match
  564.  
  565.     mov    si,offset paktype    ;is it a PAK?
  566.     mov    di,dx            ;back to filename type
  567.     mov    cx,ax            ;3 chars
  568.     repz    cmpsb            ;compare
  569.     jz    Got_Type        ;a match
  570.  
  571. ;v1.4    Adding .LZH types
  572.     mov    ftype,LZH        ;ok, assume .LZH file        v1.4
  573.  
  574.     mov    si,offset lzhtype    ;is it an LZH?
  575.     mov    di,dx            ;back to filename type
  576.     mov    cx,ax            ;3 chars
  577.     repz    cmpsb            ;compare
  578.     jz    Got_Type        ;a match
  579.  
  580. BadType:
  581.      mov    al,12            ;'Invalid file type'        v1.3a
  582.      ret                ;back to Exit            v1.3
  583.  
  584. Got_Type:                ;v1.3
  585.  
  586. ;    find first matching file
  587.  
  588.     push    ES
  589.     mov    ah,2fh            ; get current dta ptr
  590.     int    21h            ; returned in ES:bx
  591.     mov    savedta,ES
  592.     mov    savedta[2],bx
  593.     pop    ES
  594.  
  595.     mov    dx,offset dta        ; set local dta for murkers
  596.     mov    ah,1ah
  597.     int    21h
  598.  
  599.     call    OpenArc            ; see if archive exists
  600. ;    jb    ArcV_X            ;nope, return, AL = error    v1.3
  601.     jnb    ArcV1            ;ok
  602.      jmp    ArcV_X            ;nope, return, AL=error        v1.4
  603.  
  604. ;v1.3a    Display archive filename, header,
  605. ;    then into a loop for each archive member.
  606.  
  607. ArcV1:    mov    dx,fileptr        ;pointer to filename        v1.3a
  608.     call    PrintS            ;display, CR/LF            v1.3a
  609.     jb    ArcV_X            ;output failed            v1.3a
  610.  
  611.     Print    vhdr
  612.     jb    ArcV_X            ;output failed, AL = error    v1.3
  613.  
  614. ArcVNext:
  615. IF    DEBUG
  616.     Print    debug1
  617.     jmp    short debugj1
  618. debug1    db    'Calling GetHdr',CR,LF,0
  619. debugj1:
  620. ENDIF
  621.     call    GetHdr            ; load next header
  622.     jb    ArcV_NoHdr        ;failed somehow, AL=error    v1.3a
  623.                     ;(could be EOF, which is ok)    v1.3a
  624. IF    DEBUG
  625.     Print    debug2
  626.     jmp    short debugj2
  627. debug2    db    'Calling ArcVgo',CR,LF,0
  628. debugj2:
  629. ENDIF
  630.     call    ArcVgo            ;format, write out file report
  631.     jb    Arcv_NoHdr        ;something failed, AL=error    v1.3a
  632.  
  633. IF    DEBUG
  634.     Print    debug3
  635.     jmp    short debugj3
  636. debug3    db    'Calling Bump_ArcPtrs',CR,LF,0
  637. debugj3:
  638. ENDIF
  639.     call    Bump_ArcPtrs        ;bump to next archive file    v1.3
  640.     jnb    ArcVNext        ;loop if ok, else AL=error    v1.3a
  641.                     ;(could be EOF)            v1.3a
  642.  
  643. ArcV_NoHdr:
  644.     cmp    archdr.aCmpMeth,0    ; archive eof?
  645.     jnz    ArcV_X            ;nope, something else happened    v1.3
  646.  
  647.     cmp    totmbrs,0        ;any totals?            v1.3
  648.     jz    ArcV_X            ;nope                v1.3
  649.      push    ax            ;save previous error value    v1.3
  650.      call    Format_Totals        ;yep, format and output        v1.3
  651.      pop    ax            ;restore prev err value        v1.3
  652.  
  653. ArcV_X:    ret                ;AL=error            v1.3a
  654.  
  655. Start    endp                ;                v1.3
  656.  
  657.  
  658. ;v1.3    Format, display single line for each member
  659. ;    On success, return:
  660. ;     CF clear
  661. ;     AL = 0
  662. ;    On error, return:
  663. ;     CF set (because of output write fail)
  664. ;     AL = error code
  665.  
  666. ArcVgo    proc    near
  667.     mov    di,offset vname        ; copy file name
  668.     mov    si,offset archdr.aMbrName
  669.     mov    cx,word ptr 13        ;up to 12 chars long, AsciiZ 0
  670. ArcV3:
  671.     lodsb
  672.     or    al,al            ; end of name?            v1.3
  673.     je    ArcV4
  674.      stosb
  675.      loop    ArcV3
  676.      jmp    short ArcV5
  677.  
  678. ArcV4:
  679.     mov    al,' '            ; pad with blanks
  680.     rep    stosb
  681. ArcV5:
  682. ; reduce the size/length to word values
  683.  
  684.     mov    bx,offset archdr.aCmpSiz    ;-> compressed size    v1.4
  685.     mov    cx,[bx]            ;.lo                v1.4
  686.     mov    dx,2[bx]        ;.hi                v1.4
  687.     mov    bx,offset archdr.aUncmpSiz    ;-> uncompressed size    v1.4
  688.     mov    ax,2[bx]        ;.hi                v1.4
  689.     mov    bx,[bx]            ;.lo                v1.4
  690.  
  691. ArcV51: or    ax,ax            ; big number?
  692.     jz    ArcV52            ; nope, can use it
  693.      shr    ax,1            ; yup, divide by two
  694.      rcr    bx,1
  695.      shr    dx,1
  696.      rcr    cx,1
  697.      jmp    short ArcV51
  698.  
  699. ArcV52:
  700.     mov    ax,bx            ; low word of actual size
  701.     mov    sign,' '
  702.     cmp    ax,cx            ; arc member is larger?
  703.     jb    ArcV520
  704.      sub    ax,cx            ; amount saved
  705.      jmp    short ArcV56
  706.  
  707. ArcV520:
  708.     sub    ax,cx
  709.     neg    ax
  710.     mov    sign,'-'
  711.  
  712. ArcV56:
  713.     mul    hundred            ; to percentage
  714.     add    ax,50
  715.     adc    dx,0            ; round up percent
  716.     or    bx,bx            ; empty file?
  717.     jnz    ArcV53
  718.      mov    ax,100
  719.      jmp    short ArcV54
  720.  
  721. ArcV53: div    bx
  722. ArcV54:
  723.     cmp    ax,100            ; archive fouled?
  724.     jbe    ArcV55
  725.      sub    ax,ax
  726. ArcV55:
  727.     mov    di,offset vfactor-2    ;format stowage factor        v1.3
  728.     call    Asciify            ;display AX
  729.  
  730.     mov    al,sign
  731.     mov    vfactor,al
  732.  
  733.     mov    cx,word ptr 3        ;gonna need it in a sec        v1.4
  734.     cmp    ftype,LZH        ;LZH type? (compression method    v1.4
  735.                     ; is already text)        v1.4
  736.     jnz    ArcV_GetStyles        ;nope                v1.4
  737.  
  738. ;v1.4    The LZH compression method (5 chars) is still in inbuf.
  739.  
  740.     mov    si,offset inbuf.lCmpMeth    ;-> 5-char compression    v1.4
  741.                         ;   method string    v1.4
  742.     mov    di,si
  743.     add    di,5            ;point to beyond chars        v1.4
  744.     mov    ax,'  '            ;need 3 trailing blanks        v1.4
  745.     stosw
  746.     stosb
  747.     mov    di,offset vstyle+1    ;indent to be neat        v1.4
  748.     jmp    short ArcV_GotStyle    ;skip                v1.4
  749.  
  750. ArcV_GetStyles:                ;                v1.4
  751.  
  752.     mov    si,offset zstyles    ;assume ZIP            v1.3
  753.     cmp    ftype,ZIP        ;ZIP file?            v1.3
  754.     jz    ArcV55A            ;yep                v1.3
  755.      mov    si,offset styles    ;ARC or PAK            v1.3
  756. ArcV55A:                ;                v1.3
  757.  
  758.     sub    bx,bx            ; determine style
  759.     mov    bl,archdr.aCmpMeth
  760.     dec    bl            ;adjust for table offset    v1.3
  761. ;v1.4    mov    cl,3            ; eight bytes each entry
  762. ;v1.4    CX = 3 (eight bytes each entry)
  763.     shl    bx,cl    ;*8
  764.  
  765.     add    si,bx            ;point into style table        v1.3
  766.     mov    di,offset vstyle
  767.  
  768. ArcV_GotStyle:                ;                v1.4
  769.     inc    cx            ;CX=4=words to move        v1.4
  770.     rep    movsw            ;                v1.3
  771.  
  772.     mov    bx,offset archdr.aCmpSiz    ;-> compressed size    v1.4
  773.     mov    ax,[bx]            ;.lo                v1.4
  774.     mov    dx,2[bx]        ;.hi                v1.4
  775.     mov    bx,offset totsize    ;-> accumulated compressed size    v1.4
  776.     add    [bx],ax            ;.lo                v1.4
  777.     adc    2[bx],dx        ;.hi                v1.4
  778.  
  779.     mov    di,offset vsize        ;format file size        v1.3
  780.     call    Asciify_Long        ;                v1.3
  781.  
  782.     mov    bx,offset archdr.aUncmpSiz    ;-> uncompressed size    v1.4
  783.     mov    ax,[bx]            ;.lo                v1.4
  784.     mov    dx,2[bx]        ;.hi                v1.4
  785.     mov    bx,offset totlen    ;-> total length accumulator    v1.4
  786.     add    [bx],ax            ;.lo                v1.4
  787.     adc    2[bx],dx        ;.hi                v1.4
  788.     
  789.     mov    di,offset vlength    ;format file length        v1.3
  790.     call    Asciify_Long        ;                v1.3
  791.  
  792.     mov    ax,archdr.aModDate    ; format file date
  793.     call    GetDate
  794.  
  795.     mov    ax,archdr.aModTime    ; format file time
  796.     call    GetTime
  797.  
  798.     mov    ax,archdr.aCrc16    ; format crc in hex
  799.     mov    di,offset vcrc
  800.     call    Cvh
  801.  
  802.     inc    totmbrs            ;NOW bump total count        v1.3a
  803.     Print    vline            ; display this file info
  804.                     ;(may return error)        v1.3a
  805.     ret
  806.  
  807. ArcVgo    endp
  808.  
  809.  
  810.     subttl    '--- load next archive header'
  811.     page
  812.  
  813. ;v1.3    Adding ZIP file searching
  814. ;v1.3a    For ARC/PAK files, now testing to see if we're at the archive
  815. ;    file end.  If so (a proper file), return with EOF (CF set
  816. ;    but AL=0).
  817. ;    Archive files may have picked up some garbage on the end
  818. ;    (from XMODEM xfers, whatever).  We'll see if we at LEAST have
  819. ;    enough data for an archive header.
  820. ;    If not, assume EOF, ignoring garbage.
  821. ;    If there's more than 29 bytes of garbage .. the header will be
  822. ;    garbage and we're gonna report a format error .. but that's ok for now.
  823. ;    Zip files have a definite ending (the central directory,
  824. ;    and they'll look out for their own endings.
  825. ;
  826. ;    Also returning CF and AL per any errors.
  827.  
  828. GetHdr  proc    near
  829.  
  830.     xor    ax,ax            ;handy 0
  831.     mov    archdr.aCmpMeth,al    ;assume archive EOF
  832.  
  833.     cmp    ftype,ZIP        ;doing ZIP files?
  834.     jnz    GH_NotZip        ;nope                v1.4
  835.      jmp    Get_ZipHdr        ;yep, they look out for themselves
  836.  
  837. GH_NotZip:
  838.     cmp    ftype,LZH        ;doing an LZH file?        v1.4
  839.     jnz    GH_ArcPak_Hdr        ;nope                v1.4
  840.      jmp    Get_LZHHdr        ;yep                v1.4
  841.  
  842. GH_ArcPak_Hdr:                ;                v1.4
  843.  
  844. ;v1.3    New code
  845. ;    ARC/PAK headers look like this:
  846. ;aMbrFlag    db    1AH        ;unique header flag
  847. ;aCmpMeth    db    0        ;  compression code
  848. ;aMbrName    db    13 dup (0)    ;  file name
  849. ;aCmpSiz    dw    0,0        ;  file size in archive
  850. ;aModDate    dw    0        ;  creation date
  851. ;aModTime    dw    0        ;  creation time
  852. ;aCrc16        dw    0        ;  cyclic redundancy check
  853. ;aUncmpSiz    dw    0,0        ;  true file size, bytes
  854.  
  855.     mov    dx,offset archdr    ;read into here
  856.     mov    cx,ARCHDRLEN        ;nr bytes to read
  857.     mov    bx,archdl        ;archive file handle
  858.     mov    ah,3FH            ;read from file/device
  859.     int    21H
  860.     jnb    GH_ChkHdr        ;read ok            v1.3a
  861.      ret                ;return CF set, AL=error    v1.3a
  862.  
  863. GH_ChkHdr:
  864.     mov    bx,dx            ;DS:BX -> structure start    v1.3a
  865.  
  866.     cmp    [bx].aMbrFlag,ARCMARK    ;start of header?
  867.     jne    Hdr_InvalFmt        ;'invalid format', exit CF set
  868.  
  869.     mov    al,[bx].aCmpMeth    ;type compression
  870.     cmp    al,ARCVER        ;reasonable code?
  871.     ja    Hdr_InvalFmt        ;nope, funny stuff
  872.  
  873.     or    al,al            ; archive eof?
  874.     je    Hdr_RetCF        ;yep, done, return CF set
  875.                     ;but AL=0 = not a REAL error    v1.3a
  876.     cmp    al,1            ; old format?
  877.     jne    GetHdrX            ; if so, it's short
  878.      mov    si,offset archdr.aCmpSiz            ; CPC15-1C
  879.      mov    di,offset archdr.aUncmpSiz            ; CPC15-1C
  880.      movsw                ;                v1.3
  881.      movsw                ;                v1.3
  882. GetHdrX:
  883.     xor    al,al            ;return AL=0, success        v1.3a
  884.     clc
  885.     ret
  886.  
  887. Hdr_InvalFmt:
  888.     mov    al,0BH            ;'invalid format'
  889. Hdr_EarlyEOF:                ;                ;v1.4
  890.     mov    [bx].aCmpMeth,al    ;signal EOF or invalid format    v1.4
  891. Hdr_RetCF:
  892.     stc                ;return CF set, AL=error
  893.     ret
  894.  
  895. GetHdr    endp
  896.  
  897.  
  898. Get_ZipHdr    proc    near
  899. ;v1.4    GetHdr Subroutine for ZIP files
  900. ;v1.3    Reads in ZIP file entry.
  901. ;    Then scans for the unique file entry signature.
  902. ;    On success:
  903. ;     DS:BX -> file entry directory structure
  904. ;     CF clear
  905. ;    Else CF set for failure
  906.  
  907.     call    Read_Zip_Entry
  908.     jb    Get_ZHdrX            ;failed, AL=ERRORLEVEL
  909.  
  910.     mov    bx,offset inbuf            ;use for field base
  911.     mov    di,offset archdr.aCmpMeth    ;moving into this structure
  912.  
  913. ;v1.4    Remember, the ZIP header we'll be snarfing data from
  914. ;    looks like this:
  915. ;zVerMade    dw    ?    ;version needed to extract    2 bytes
  916. ;zBitflag    dw    ?    ;general purpose bit flag    2 bytes
  917. ;zCmpMeth    dw    ?    ;compression method        2 bytes
  918. ;zModTime    dw    ?    ;last mod file time         2 bytes
  919. ;zModDate    dw    ?    ;last mod file date        2 bytes
  920. ;zCrc32        dw    ?,?    ;crc-32               4 bytes
  921. ;zCmpSiz    dw    ?,?    ;compressed size        4 bytes
  922. ;zUncmpSiz    dw    ?,?    ;uncompressed size        4 bytes
  923. ;zNameLen    dw    ?    ;filename length        2 bytes
  924. ;zExtraLen    dw    ?    ;extra field length        2 bytes
  925. ;zMbrName    db    ?    ;filename (variable size)
  926.                 ;extra field (variable size)
  927. ;
  928. ;    and the ARC/PAK record we'll be formatting to
  929. ;    looks like this:
  930. ;aMbrFlag db    1AH
  931. ;aCmpMeth db    0            ;  compression code
  932. ;aMbrName db    13 dup (0)        ;  file name
  933. ;aCmpSiz dw    0,0            ;  file size in archive
  934. ;aModDate dw    0            ;  creation date
  935. ;aModTime dw    0            ;  creation time
  936. ;aCrc16  dw    0            ;  cyclic redunancy check
  937. ;aUncmpSiz  dw    0,0            ;  true file size, bytes
  938.  
  939.     mov    ax,[bx].zCmpMeth        ;compression method
  940.     inc    al                ;bump to be non-0
  941.     stosb                    ;->  aCmpMeth
  942.  
  943. ;For now, assuming a normal file name (no paths)
  944.  
  945.     mov    ax,[bx].zNameLen        ;filename length
  946.     and    ax,15                ;constrain to max 12 chars
  947.     mov    cx,ax                ;into CX for move
  948.     lea    si,[bx].zMbrName        ;pointer to actual filename
  949.     rep    movsb                ;do the move
  950.     xor    al,al                ;terminating 0
  951.     stosb
  952.  
  953.     mov    di,offset archdr.aCmpSiz    ;bump past name
  954.  
  955. ;    mov    ax,[bx].zCmpSiz            ;compressed size.lo
  956. ;    stosw                    ; -> aCmpSiz
  957. ;    mov    ax,[bx].zCmpSiz[2]        ;compressed size.hi
  958. ;    stosw                    ; -> aCmpSiz[2]
  959.     mov    si,offset inbuf.zCmpSiz        ;-> compressed size
  960.     movsw                    ;aCmpSiz.lo
  961.     movsw                    ;aCmpSiz.hi
  962.  
  963.     mov    ax,[bx].zModDate        ;last mod date
  964.     stosw                    ; -> aModDate
  965.     mov    ax,[bx].zModTime        ;last mod time
  966.     stosw                    ; -> aModTime
  967.     mov    ax,[bx].zCrc32            ;CRC-32 value.lo
  968.     stosw                    ; -> aCrc16
  969.  
  970. ;    mov    ax,[bx].zUncmpSiz        ;uncompressed size.lo
  971. ;    stosw                    ; -> aUncmpSiz
  972. ;    mov    ax,[bx].zUncmpSiz[2]        ;uncompressed size.hi
  973. ;    stosw                    ; -> aUncmpSiz[2]
  974.     mov    si,offset inbuf.zUncmpSiz    ;-> uncompressed size
  975.     movsw                    ;aUncmpSiz.lo
  976.     movsw                    ;aUncmpSiz.hi
  977.  
  978.     xor    ax,ax                ;return AX 0
  979.     clc                    ;return CF clear
  980. Get_ZHdrX:
  981.     ret
  982.  
  983. Get_ZipHdr    endp        ;GetHdr subroutine
  984.  
  985.  
  986.  
  987. Get_LZHHdr    proc    near
  988. ;v1.4    GetHdr Subroutine for LZH headers
  989. ;    LZH file header has already been read in to inbuf.
  990. ;
  991. ;    If all is ok, we move the appropriate LZH fields into the
  992. ;    standard ARC/PAK structure (archdr) (so far as we can).
  993. ;
  994. ;    Gleaning from the LHARCDOC documentation, the 'laCmpMeth' field
  995. ;    (5 characters) can be:
  996. ;        '-lh0-'        stored as is (no compression)
  997. ;        '-lh1-'        compressed by LZHuf coding
  998. ;    There appear to be at least two more possible compression codes
  999. ;    that may appear:  "LARC type 4 and type 5" (whatever they may be!).
  1000. ;
  1001. ;    Assuming this field will ALWAYS be text, we are NOT gonna try to
  1002. ;    snarf some magic code number out of the field, but will just
  1003. ;    protect the field (in inbuf) and move the text directly into our
  1004. ;    formatted display line later.
  1005. ;
  1006. ;    The only way we can test this as an LZH header is to look
  1007. ;    for a '-%%%-' starting at the 2d header byte (the laCmpMeth
  1008. ;    field).
  1009. ;
  1010. ;    On success:
  1011. ;     DS:BX -> file entry directory structure
  1012. ;     CF clear
  1013. ;    Else CF set for failure
  1014.  
  1015. ;v1.4    LZH files don't have a decent, clean EOF header.
  1016. ;    We have to test for near-EOF the hard way.
  1017.  
  1018.     mov    di,offset archdr.aMbrFlag    ;moving into this structure
  1019.     mov    ax,001AH            ;fake ARC/PAK flag
  1020.     stosw                    ; and EOF compression code
  1021.  
  1022.     xor    ax,ax            ;handy 0
  1023.     mov    bx,offset filelen    ;-> file length
  1024.     mov    dx,[bx]            ;file length.lo
  1025.     mov    cx,2[bx]        ;file length.hi
  1026.  
  1027.     mov    bx,offset curpsn    ;for fast access    
  1028.     cmp    cx,2[bx]        ;length.hi = psn.hi?
  1029.     jnz    GL_AddHdr        ;nope
  1030.     cmp    dx,[bx]            ;length.lo = psn.lo?
  1031.     jz    GL_TrueEof        ;yep, we're exactly at EOF
  1032.  
  1033. GL_AddHdr:
  1034.     sub    dx,LZHHDRLEN        ;sub header length
  1035.     sbb    cx,ax    ;0        ;handle the borrow
  1036.     jb    GL_Eof            ;<0, beyond EOF
  1037.     sub    dx,[bx]            ;- file psn.lo
  1038.     sbb    cx,2[bx]        ;- file psn.hi, minus any borrows
  1039.     jnb    GL_NotEof        ;not near end .. ok
  1040.  
  1041. ;There must've been junk on the file end.
  1042. ;However .. there ALWAYS seems to be junk on the end.
  1043. ; So .. we'll return no message at all (AL=0)
  1044. ;If we ever figure out how to detect a TRUE LZH EOF,
  1045. ;we can enable this ERRORLEVEL=18 business.
  1046.  
  1047. GL_Eof:
  1048. ;    mov    al,18            ;'No further files to be found'
  1049. GL_TrueEof:
  1050.     stc                ;CF set for EOF            v1.4
  1051.     ret
  1052.  
  1053. GL_NotEof:
  1054.  
  1055.     push    di            ;save ptr -> archdr.aMbrName
  1056.     call    Read_LZH_Entry
  1057.     pop    di
  1058.     jb    Get_LHdrX            ;failed, AL=ERRORLEVEL
  1059.  
  1060.     mov    bx,offset inbuf            ;use for field base
  1061.  
  1062. ;v1.4    Remember, the LZH header we'll be snarfing data from
  1063. ;    looks like this:
  1064. ;lUnk1    db    ?,?    ;char unknown1[2];    ;?
  1065. ;lCmpMeth    db    5 dup(?) ;char method[5];    ;compression method
  1066. ;lCmpSiz    dw    ?,?    ;long csize;    ;compressed size
  1067. ;lUncmpSiz    dw    ?,?    ;long fsize;    ;uncompressed size
  1068. ;lModTime    dw    ?    ;int ftime;    ;last mod file time
  1069. ;                        ; (msdos format)
  1070. ;lModDate    dw    ?    ;int fdate;    ;last mod file date
  1071. ;lfAttr        db    ?    ;char fattr;    ;file attributes
  1072. ;unknown2    db    ?    ;char unknown2;    ;?
  1073. ;lNameLen    db    ?    ;char namelen;    ;filename length
  1074. ;
  1075. ;lMbrName    db    ?    ;char *fname;    ;filename
  1076. ;;lCrc16    dw    ?    ;int crc;    ;crc-16
  1077. ;
  1078. ;    and the ARC/PAK record we'll be formatting to
  1079. ;    looks like this:
  1080. ;aMbrFlag db    1AH
  1081. ;aCmpMeth db    0            ;  compression code
  1082. ;aMbrName db    13 dup (0)        ;  file name
  1083. ;aCmpSiz dw    0,0            ;  file size in archive
  1084. ;aModDate dw    0            ;  creation date
  1085. ;aModTime dw    0            ;  creation time
  1086. ;aCrc16  dw    0            ;  cyclic redundancy check
  1087. ;aUncmpSiz  dw    0,0            ;  true file size, bytes
  1088.  
  1089.     mov    al,[bx].lNameLen        ;filename length
  1090.     and    ax,15                ;constrain to max 12 chars
  1091.     mov    cx,ax                ;into CX for move
  1092.     mov    si,offset inbuf.lMbrName    ;-> actual filename
  1093.     rep    movsb                ;do the move
  1094.     xor    al,al                ;terminating 0
  1095.     stosb
  1096.  
  1097. ;In LZH headers, the 2-byte CRC16 word lies immediately
  1098. ;after the filename.
  1099. ;Snarf it now and stuff in the ARC header.
  1100.  
  1101.     lodsw                    ;lCrc16
  1102.     push    ax                ;save a sec
  1103.  
  1104.     mov    di,offset archdr.aCmpSiz    ;bump past name
  1105.  
  1106. ;    mov    ax,[bx].lCmpSiz            ;compressed size.lo
  1107. ;    stosw                    ; -> aCmpSiz
  1108. ;    mov    ax,[bx].lCmpSiz[2]        ;compressed size.hi
  1109. ;    stosw                    ; -> aCmpSiz[2]
  1110.     mov    si,offset inbuf.lCmpSiz        ;-> compressed size
  1111.     movsw                    ;aCmpSiz.lo
  1112.     movsw                    ;aCmpSiz.hi
  1113.  
  1114.     mov    ax,[bx].lModDate        ;last mod date
  1115.     stosw                    ; -> aModDate
  1116.     mov    ax,[bx].lModTime        ;last mod time
  1117.     stosw                    ; -> aModTime
  1118.     pop    ax                ;CRC-16 value
  1119.     stosw                    ; -> aCrc16
  1120. ;    mov    ax,[bx].lUncmpSiz        ;uncompressed size.lo
  1121. ;    stosw                    ; -> aUncmpSiz
  1122. ;    mov    ax,[bx].lUncmpSiz[2]        ;uncompressed size.hi
  1123. ;    stosw                    ; -> aUncmpSiz[2]
  1124.     mov    si,offset inbuf.lUncmpSiz    ;-> uncompressed size
  1125.     movsw                    ;aUncmpSiz.lo
  1126.     movsw                    ;aUncmpSiz.hi
  1127.  
  1128.     xor    ax,ax                ;return AX 0
  1129.     clc                    ;return CF clear
  1130. Get_LHdrX:
  1131.     ret
  1132.  
  1133. Get_LZHHdr    endp            ;GetHdr Subroutine        v1.4
  1134.  
  1135.  
  1136. Read_LZH_Entry    proc    near        ;GetHdr Subroutine        v1.4
  1137.  
  1138.     mov    dx,offset inbuf            ;read into here
  1139.     mov    cx,LZHHDRLEN            ;entry structure size
  1140.                         ;(does NOT include variable
  1141.                         ; length filename, and the
  1142.                         ;two CRC bytes following the
  1143.                         ;filename)
  1144.     mov    bx,archdl            ;file handle
  1145.     call    ReadZ_It            ;try to read in header
  1146.                         ;(up to filename)
  1147.     jb    ReadL_Eof            ;failed, AL=error
  1148.  
  1149.     mov    si,dx                ;structure start
  1150.     mov    al,'-'                ;test for '-l%-' or whatever
  1151.     cmp    [si].lCmpMeth,al        ;first part of compression
  1152.                         ;method string?
  1153.     jnz    ReadL_InvalDat            ;bogus, failed
  1154.      cmp    [si].lCmpMeth+4,al        ;how about last char?
  1155.      jz    ReadL_Ok1            ;yep, fine
  1156. ReadL_InvalDat:
  1157.     mov    al,0DH                ;force to 'invalid data'
  1158. ReadL_Eof:
  1159.     mov    archdr.aCmpMeth,al        ;set per EOF or error
  1160.     stc                    ;return CF set
  1161.     ret
  1162.  
  1163. ReadL_Ok1:
  1164.     mov    dx,offset inbuf.lMbrName    ;-> lMbrName psn
  1165.     mov    cl,inbuf.lNameLen        ;length of member filename
  1166.     xor    ch,ch                ;clear msb
  1167.     call    ReadZ_It            ;read in the name
  1168.     jb    ReadL_Eof            ;failed
  1169.     add    dx,cx                ;bump buff ptr past name
  1170.     mov    cx,2                ;LZH CRC is a word
  1171.     call    ReadZ_It            ;read in the CRC word
  1172.     jb    ReadL_Eof            ;failed
  1173.     ret                    ;success
  1174.  
  1175. Read_LZH_Entry    endp            ;GetHdr Subroutine        v1.4
  1176.  
  1177.  
  1178. Read_Zip_Entry    proc    near        ;GetHdr Subroutine
  1179.  
  1180.     mov    dx,offset inbuf            ;read into here
  1181.     mov    cx,ZIPHDRLEN            ;entry structure size
  1182.                         ;(does NOT include filename or
  1183.                         ; Extra fields, which are
  1184.                         ;dynamic)
  1185.     mov    bx,archdl            ;file handle
  1186.     call    ReadZ_It            ;try to read in header
  1187.                         ;(up to filename)
  1188.     jb    ReadZ_Eof            ;failed, AL=error    v1.3a
  1189.  
  1190.     mov    si,dx                ;->file signature    v1.4
  1191.     lodsw                    ;snarf first 2 chars    v1.4
  1192.     cmp    ax,ZSIG                ;ZIP header?        v1.4
  1193.     jnz    ReadZ_InvalDat            ;nope, bogus        v1.4
  1194.     lodsw                    ;file or central sig    v1.4
  1195.     cmp    ax,ZFILESIG            ;next member?        v1.4
  1196.     jz    ReadZ_Ok1            ;yep, fine        v1.4
  1197.     cmp    ax,ZDIRSIG            ;central directory?    v1.4
  1198.                         ;(means we're done)    v1.4
  1199.     mov    al,0                ;assume yes, EOF    v1.4
  1200.     jz    ReadZ_Eof            ;yep            v1.4
  1201.  
  1202. ReadZ_InvalDat:
  1203.     mov    al,0DH                ;'Invalid data'        v1.4
  1204. ReadZ_Eof:                    ;            v1.3a
  1205.     mov    archdr.aCmpMeth,al        ;set per EOF or error    v1.3a
  1206.     stc                    ;return CF set        v1.3a
  1207.     ret
  1208.  
  1209. ReadZ_Ok1:
  1210.     mov    dx,offset inbuf.zMbrName    ;move to zFilename psn
  1211.     mov    cx,inbuf.zNameLen        ;length of member filename
  1212.                         ;fall thru to ...    v1.3a
  1213.  
  1214. ;v1.4    Common subroutine for ReadZ and Read_LZH
  1215. ;    DX -> buffer
  1216. ;    CX = bytes to read
  1217. ;    BX MUST have archdl .. so protect BX!
  1218.  
  1219. ReadZ_It:
  1220.     mov    ah,3FH                ;read from file/device
  1221.     int    21H
  1222.     jb    ReadZ_ItX            ;failed, error in AX    v1.3a
  1223.  
  1224. ;v1.4    We'll update our curpsn file pointers later
  1225. ;    when we try to read past compressed file contents.
  1226.  
  1227. ;v1.4     add    curpsn,ax            ;bump current file ptr    v1.3a
  1228.                         ;by amount read        v1.3a
  1229. ;v1.4     adc    word ptr curpsn[2],0        ;bump psn.hi if carry    v1.3a
  1230.  
  1231.      cmp    ax,cx                ;read all we expected?
  1232.      mov    ax,0                ;clear AX        v1.3a
  1233.      jz    ReadZ_ItX            ;yep, return CF clear    v1.3a
  1234.       mov    al,0BH                ;assume unexpected EOF
  1235.                         ;('invalid format')
  1236.       stc
  1237. ReadZ_ItX:
  1238.     ret                    ;CF, AL set per error    v1.3a
  1239.  
  1240. Read_Zip_Entry    endp            ;GetHdr subroutine
  1241.  
  1242.  
  1243. ;v1.3    Common subroutine
  1244. ;    Bumps archive file pointers to next entry
  1245. ;    On success, return:
  1246. ;     CF clear
  1247. ;     AL = 0
  1248. ;    On failure (e.g., couldn't move ptrs), return:
  1249. ;     CF set
  1250. ;     AL = error
  1251.  
  1252. Bump_ArcPtrs    proc    near
  1253.  
  1254.     cmp    ftype,ZIP        ;ZIP file?            v1.3
  1255.     jz    Next_ZEntry        ;bump file ptr to next entry    v1.3
  1256.  
  1257. ;v1.3    Entirely new code
  1258.  
  1259.     mov    bx,offset archdr.aCmpSiz    ;-> encoded file length    v1.4
  1260.     mov    dx,[bx]            ;.lo                v1.4
  1261.     mov    cx,2[bx]        ;.hi
  1262.     jmp    short Bump_Common    ;common code
  1263.  
  1264.  
  1265. ;v1.3    Positions ZIP file pointer to next local entry.
  1266. ;    We've already read in the entire header, plus the filename,
  1267. ;    so the file pointer should be just beyond the filename
  1268. ;    (at the Extra field).
  1269. ;    Move file pointers beyond the Extra field, and then past
  1270. ;    the actual entry data (the compressed size).
  1271.  
  1272. Next_ZEntry:
  1273.  
  1274.     mov    bx,offset inbuf            ;point back to structure
  1275.     mov    dx,[bx].zCmpSiz            ;size.lo
  1276.     mov    cx,[bx].zCmpSiz[2]        ;size.hi
  1277.     add    dx,[bx].zExtraLen        ;add in extra field length
  1278.     adc    cx,0                ;in case of carry
  1279.  
  1280. Bump_Common:
  1281.  
  1282.     mov    bx,archdl            ;file handle
  1283.     mov    ax,4201H            ;move pointer from current loc
  1284.     int    21H
  1285.     jb    Bump_X                ;seek error        v1.3a
  1286.                         ;return CF set, AL=error v1.3a
  1287.  
  1288. ;v1.4    Updating curpsn variables now
  1289. ;    so the NEXT GetHdr call will have current data.
  1290.      mov    bx,offset curpsn
  1291.      mov    [bx],ax
  1292.      mov    2[bx],dx
  1293.      xor    ax,ax                ;AX,CF clear        v1.3a
  1294. Bump_X:
  1295.     ret
  1296.  
  1297. Bump_ArcPtrs    endp
  1298.  
  1299.  
  1300. ;v1.3    Formats, displays totals
  1301.  
  1302. Format_Totals    proc    near
  1303.  
  1304.     mov    ax,totmbrs        ;total members            v1.3
  1305.     mov    di,offset vtmbrs-2    ;format total members        v1.3
  1306.     call    Asciify            ;                v1.3
  1307.  
  1308.     mov    bx,offset totlen    ;-> total actual file size    v1.4
  1309.     mov    ax,[bx]            ;.lo                v1.4
  1310.     mov    dx,2[bx]        ;.hi                v1.4
  1311.  
  1312.     push    ax            ;save totlen.lo            v1.4
  1313.     push    dx            ; and totlen.hi            v1.4
  1314.  
  1315.     mov    di,offset vtlen        ;format total actual file size    v1.3
  1316.     call    Asciify_Long        ;                v1.3
  1317.  
  1318.     mov    bx,offset totsize    ;-> total compressed file sizes    v1.4
  1319.     mov    ax,[bx]            ;.lo                v1.4
  1320.     mov    dx,2[bx]        ;.hi                v1.4
  1321.  
  1322.     push    ax            ;save totsize.lo        v1.4
  1323.     push    dx            ; and totsize.hi        v1.4
  1324.  
  1325.     mov    di,offset vtsize    ;format total archive file size    v1.3
  1326.     call    Asciify_Long        ;                v1.3
  1327.  
  1328. ; reduce the total size/length to word values
  1329.  
  1330.     pop    dx            ;totsize.hi            v1.4
  1331.     pop    cx            ;totsize.lo            v1.4
  1332.     pop    ax            ;totlen.hi            v1.4
  1333.     pop    bx            ;totlen.lo            v1.4
  1334.  
  1335. ArcV2b: or    ax,ax            ; big number?
  1336.     jz    ArcV2c            ; nope, can use it
  1337.      shr    ax,1            ; yup, divide by two
  1338.      rcr    bx,1
  1339.      shr    dx,1
  1340.      rcr    cx,1
  1341.      jmp    short ArcV2b
  1342.  
  1343. ArcV2c:
  1344.     mov    ax,bx
  1345.     mov    sign,' '        ; whata kludge
  1346.     cmp    ax,cx            ; arc is bigger than orig?
  1347.     jb    ArcV2c1
  1348.      sub    ax,cx            ; amount saved
  1349.      jmp    short ArcV2f
  1350.  
  1351. ArcV2c1:
  1352.     sub    ax,cx
  1353.     neg    ax
  1354.     mov    sign,'-'
  1355.  
  1356. ArcV2f:
  1357.     mul    hundred            ; to percentage
  1358.     add    ax,50
  1359.     adc    dx,0            ; round up percent
  1360.     or    bx,bx            ; empty file?
  1361.     jnz    ArcV2d
  1362.      mov    ax,100
  1363.      jmp    short ArcV2e
  1364.  
  1365. ArcV2d: div    bx
  1366. ArcV2e:
  1367.     mov    di,offset vtsf-2    ;format stowage factor        v1.3
  1368.     call    Asciify            ;AX                v1.3
  1369.  
  1370.     mov    al,sign
  1371.     mov    vtsf,al
  1372.     Print    vthdr            ; display totals
  1373.     ret
  1374.  
  1375. Format_Totals    endp
  1376.  
  1377.  
  1378. OpenArc proc    near            ; open new archive
  1379.  
  1380.     mov    dx,offset arcname
  1381.     mov    ax,3d00h        ; for input
  1382.     int    21h
  1383.     jnb    Open_GetSize        ;opened ok            v1.3a
  1384.      ret                ;return CF set, AL=error    v1.3a
  1385.  
  1386. Open_GetSize:
  1387.     mov    bx,ax            ;handle into BX            v1.3a
  1388.     mov    archdl,ax        ; save file handle
  1389.  
  1390. ;v1.3a    We get the total file size now for later EOF testing.
  1391.     xor    dx,dx            ;0 offset
  1392.     xor    cx,cx
  1393.     mov    ax,4202H        ;from file end
  1394.     int    21H
  1395.     mov    filelen,ax        ;length.low
  1396.     mov    filelen[2],dx        ;length.hi
  1397.     xor    cx,cx            ;back to start
  1398.     xor    dx,dx
  1399.     mov    ax,4200H        ;psn file pointer from start
  1400.     int    21H
  1401.     ret                ;CF should be clear
  1402.  
  1403. OpenArc endp
  1404.  
  1405.  
  1406. ClosArc proc    near
  1407.  
  1408.     mov    bx,archdl        ; previous handle
  1409.     or    bx,bx            ; already open?
  1410.     jz    Closed
  1411.      mov    ah,3eh            ; yes, so close it
  1412.      int    21H
  1413. Closed:    mov    archdl,0        ;flag as closed
  1414.     ret
  1415.  
  1416. ClosArc endp
  1417.  
  1418. ;
  1419. ;    print null-terminated (AsciiZ) string like int 21h function 9
  1420. ;    Enter with DS:DX -> AsciiZ string
  1421. ;    destroys AX
  1422. ;    On success, return:
  1423. ;     CF clear
  1424. ;     AL = 0
  1425. ;    On failure (write fail), return:
  1426. ;     CF set
  1427. ;     AL = error
  1428.  
  1429. PrintS  proc    near
  1430.  
  1431.     push    di            ;v1.3
  1432.     push    bx
  1433.     push    cx
  1434.  
  1435.     mov    cx,0FFFFH        ;max scan            v1.3
  1436.     xor    al,al            ;handy 0            v1.3
  1437.     mov    di,dx            ;string start            v1.3
  1438.     repne    scasb            ;find the terminator        v1.3
  1439.     inc    cx            ;adjust                v1.3
  1440.     not    cx            ;CX=length            v1.3
  1441.  
  1442.     mov    bx,outhdl        ; using std out or temp file
  1443.     or    bx,bx            ;never opened?            v1.3
  1444.     jnz    Print_S1        ;nope, we got a handle        v1.3
  1445.      inc    bx            ;make it StdErr            v1.3
  1446.      inc    bx
  1447. Print_S1:                ;                v1.3
  1448.     mov    ah,40h            ; write to file
  1449.     int    21h
  1450.     jnb    PrintS_Done        ;fine                v1.3
  1451.  
  1452. ;v1.3    What happens if we're trying to write to an output file
  1453. ;    and THAT fails?  Even error msgs can't get out.
  1454. ;    We switch to StdErr, that's what!
  1455.  
  1456.     mov    di,ax            ;save error level        v1.3a
  1457.     mov    bx,STDERR        ;force to STdErr        v1.3a
  1458.     mov    outhdl,bx        ;and for future output        v1.3a
  1459.     mov    ah,40H            ;write to STDOUT        v1.3a
  1460.     int    21H            ;(CX,DX unchanged)        v1.3a
  1461.     mov    ax,di            ;restore orig error        v1.3a
  1462.     stc                ;return CF set            v1.3a
  1463.  
  1464. PrintS_Done:
  1465.     pop    cx            ; recover registers
  1466.     pop    bx
  1467.     pop    di
  1468.     ret
  1469.  
  1470. PrintS  endp
  1471.  
  1472.     page
  1473. ;
  1474. ;    format the time (in AX)
  1475.  
  1476. time    record  hour:5,min:6,sec:5    ;packed time
  1477.  
  1478. GetTime proc    near            ;format the date
  1479.     mov    di,offset vtime
  1480.     or    ax,ax            ;it is zero?
  1481.     jz    GotTime
  1482.  
  1483.     push    ax            ;save date
  1484.     and    ax,mask hour        ;get hour part
  1485.     mov    cl,hour            ;bits to shift
  1486.     shr    ax,cl
  1487.     call    Cnvrt1
  1488.     stosw
  1489.     mov    al,':'
  1490.     stosb
  1491.  
  1492. GT3:    pop    ax            ;get the time back
  1493.     and    ax,mask min        ;get min part
  1494.     mov    cl,min            ;bits to shift
  1495.     call    Cnvrt
  1496.     stosw
  1497. GotTime:ret
  1498. GetTime endp
  1499.  
  1500.  
  1501. Cnvrt2  proc    near            ;convert to ascii
  1502.     call    Cnvrt
  1503.     cmp    al,'0'            ;suppress leading zero
  1504.     jne    Cnvrtd
  1505.      mov    al,' '
  1506.      ret
  1507.  
  1508. Cnvrt:  shr    ax,cl
  1509. Cnvrt1: aam                ;make al into bcd
  1510.     or    ax,'00'            ; and to ascii
  1511.     xchg    al,ah
  1512. Cnvrtd: ret
  1513. Cnvrt2  endp
  1514.  
  1515.     page
  1516. ;
  1517. ;    format the date (in AX)
  1518.  
  1519. date    record  yr:7,mo:4,dy:5        ;packed date
  1520.  
  1521. GetDate proc    near            ;format the date
  1522.     or    ax,ax            ;is it zero?
  1523.     jz    GotDate
  1524.  
  1525.     push    ax            ;save date
  1526.     and    ax,mask yr        ;get year part
  1527.     mov    cl,yr            ;bits to shift
  1528.     call    Cnvrt
  1529.     mov    di,offset vyear
  1530.     or    al,'8'            ;adjust for base year
  1531.     stosw
  1532.  
  1533.     pop    bx            ;get the date back
  1534.     push    bx            ;save it
  1535.     and    bx,mask mo        ;get month part
  1536.     mov    cl,mo            ;bits to shift
  1537.     shr    bx,cl
  1538.     add    bx,bx            ; form month table index
  1539.     add    bx,bx
  1540.     lea    si,word ptr months-4[bx]
  1541.     mov    cx,word ptr 3
  1542.     mov    di,offset vmonth
  1543.     rep    movsb
  1544.  
  1545.     pop    ax            ;get the date back
  1546.     and    ax,mask dy        ;get day part
  1547.     mov    cl,dy            ;bits to shift
  1548.     call    Cnvrt
  1549.     mov    di,offset vdate
  1550.     stosw
  1551. GotDate:ret
  1552. GetDate endp
  1553.  
  1554.     page
  1555. ;
  1556. ;v1.3    A severely hacked single/double precision number conversion function.
  1557. ;    Originally from JMODEM, but severely hacked by Toad Hall.
  1558. ;    ES:DI -> string
  1559. ;    Destroys everything almost.
  1560.  
  1561. ;Enter here if integer in AX
  1562. Asciify    proc    near
  1563.  
  1564.     xor    dx,dx            ; clear fake long.hi
  1565.     mov    si,ax            ;move integer into SI
  1566.     xor    ah,ah            ;clear msb (flag)
  1567.     jmp    short Ascii_Ax        ;jump into the code
  1568.  
  1569. ;Enter here if long integer in DX:AX.
  1570. Asciify_Long:
  1571.  
  1572.     mov    si,ax            ;move long.lo into SI
  1573.     xor    ah,ah            ;clear msb (flag)
  1574. Comment    ~
  1575.     MOV    CX,3B9AH        ; Get billions
  1576.     MOV    BX,0CA00H
  1577.     CALL    Subtr            ; Subtract them out
  1578.  
  1579.     MOV    CX,05F5H        ; Get hundred-millions
  1580.     MOV    BX,0E100H
  1581.     CALL    Subtr            ; Subtract them out
  1582. Comment    ends    ~
  1583.  
  1584.     and    dx,4FFH            ;seems likely            v1.3
  1585.     MOV    CX,word ptr 0098H    ; Get ten-millions
  1586.     MOV    BX,9680H
  1587.     CALL    Subtr            ; Subtract them out
  1588.  
  1589.     MOV    CX,word ptr 000FH    ; Get millions
  1590.     MOV    BX,4240H
  1591.     CALL    Subtr            ; Subtract them out
  1592.  
  1593.     MOV    CX,word ptr 1        ; Get hundred-thousands
  1594.     MOV    BX,86A0H
  1595.     CALL    Subtr            ; Subtract them out
  1596.  
  1597. Ascii_Ax:
  1598.     xor    cx,cx            ; Get ten-thousands
  1599.     MOV    BX,2710H
  1600.     CALL    Subtr            ; Subtract them out
  1601.     MOV    BX,03E8H
  1602.     CALL    Subtr            ; Subtract them out
  1603.  
  1604.     MOV    BX,word ptr 0064H
  1605.     CALL    Subtr            ; Subtract them out
  1606.     MOV    BX,word ptr 10
  1607.     CALL    Subtr            ; Subtract them out
  1608.     mov    ax,si            ;residual in SI
  1609.     add    AL,'0'            ; Add bias to residual
  1610.     stosb                ; Put in the string
  1611.     RET
  1612.  
  1613. ;Common subroutine for Asciify
  1614.  
  1615. Subtr:    mov    al,'0'-1
  1616.  
  1617. Subtr1:    INC    al            ; Bump the digit character
  1618.     SUB    si,BX            ; Dword subtraction
  1619.     SBB    DX,CX
  1620.     JNB    Subtr1            ; Continue until a carry
  1621.  
  1622.     ADD    si,BX            ; One too many, add back
  1623.     ADC    DX,CX            ;   and the remainder
  1624.  
  1625.     cmp    al,'0'
  1626.     jnz    Subtr2            ;nope, turn off leading flag, stuff
  1627.      or    ah,ah            ;no more leading spaces?
  1628.      jnz    Sub_Stuff        ;right, stuff the '0'
  1629.       mov    al,' '            ;make it neat with leading spaces
  1630. Sub_Stuff:
  1631.     stosb                ;stuff the char
  1632.     RET
  1633.  
  1634. Subtr2:    inc    ah            ;turn off leading space flag
  1635.     stosb
  1636.     ret
  1637. Asciify    ENDP
  1638.  
  1639.  
  1640. ;v1.3a    Convert 16-bit binary word in AX
  1641. ;    to hex ASCII string at ES:DI
  1642. ;    (No need to save any registers)
  1643.  
  1644. hexchar db    '0123456789ABCDEF'
  1645.  
  1646. Cvh    proc    near
  1647.  
  1648.     mov    si,offset hexchar    ;for faster access        v1.3a
  1649.     mov    dx,ax            ; save 16-bits
  1650.  
  1651.     mov    bl,dh            ; third nibble
  1652.     mov    cx,0F04H        ;CL=4 for shifting,        v1.3a
  1653.                     ;CH=0FH for masking        v1.3a
  1654.     shr    bl,cl
  1655.     mov    al,[si][bx]        ;snarf hex char            v1.3a
  1656.     stosb
  1657.  
  1658.     mov    bl,dh            ; last nibble
  1659.     and    bl,ch    ;0fh        ;                v1.3a
  1660.     mov    al,[si][bx]        ;snarf hex char            v1.3a
  1661.     stosb
  1662.  
  1663.     mov    bl,dl            ; first nibble
  1664.     sub    bh,bh
  1665.     shr    bl,cl            ; isolate (CL still 4)        v1.3a
  1666.     mov    al,[si][bx]        ;snarf hex char            v1.3a
  1667.     stosb
  1668.  
  1669.     mov    bl,dl            ; second nibble
  1670.     and    bl,ch    ;0fh        ; isolate            v1.3a
  1671.     mov    al,[si][bx]        ;snarf hex char            v1.3a
  1672.     stosb
  1673.     ret
  1674.  
  1675. Cvh    endp
  1676.  
  1677.     subttl    '--- i/o data areas'
  1678.  
  1679. ArcV    endp
  1680.  
  1681. archdr  db    30 dup (0)        ; i/o area for a header        v1.3a
  1682.  
  1683. inbuf    db    INBUFSZ dup (0)        ;just big enough for ZIP
  1684.                     ;directories and filenames    v1.3a
  1685.  
  1686. CSEG    ENDS
  1687.     END
  1688.